package wikisearch.coref;

import java.util.*;

import wikisearch.similarity.*;
import wikisearch.datastructures.*;

public class Coreferer {

	/**
	 * Calculates coreference value of two documents, given link. It then normalizes according to number of 'rounds' it had run.
	 * 
	 * @param firstDoc String representation of entire document
	 * @param firstLinks <key : word in link, vector : indices> pair of links
	 * @param fwordIdx <word, vector of indices> pair of words
	 * @param secondDoc String representation of entire document
	 * @param secondLinks <key : word in link, vector : indices> pair of links
	 * @param swordIdx <word, vector of indices> pair of words
	 * @param windowSize size of window to extend from the links.
	 * @param sf scoring function to use.
	 * @return coreference score
	 */
	public static double getCoref(String [] firstDoc, ParserMap firstLinks, ParserMap fwordIdx, 
									String [] secondDoc, ParserMap secondLinks, ParserMap swordIdx, 
									int windowSize, ScoreFunction sf) {
		
		double firstScore = getCoref(firstDoc, firstLinks, secondDoc, secondLinks, swordIdx, windowSize, sf);
		double secondScore = getCoref(secondDoc, secondLinks, firstDoc, firstLinks, fwordIdx, windowSize, sf);
		
		int len = firstLinks.size() + secondLinks.size() + firstDoc.length + secondDoc.length;
		return (firstScore * (double)(firstLinks.size()+firstDoc.length) 
				+ secondScore * (double)(secondLinks.size() + secondDoc.length));
	}
	
	/**
	 * Gets the coreference score while iterating through 'firstLinks' variable.
	 * 
	 * @param firstDoc
	 * @param firstLinks
	 * @param secondDoc
	 * @param secondLinks
	 * @param swordIdx
	 * @param windowSize
	 * @param sf
	 * @return coreference score with 'firstLinks' as its index
	 */
	private static double getCoref(String [] firstDoc, ParserMap firstLinks, 
			String [] secondDoc, ParserMap secondLinks, ParserMap swordIdx, 
			int windowSize, ScoreFunction sf) {

		double corefLinkScore = 0.0; //coreference score consisting of links only.
		double corefWordScore = 0.0; //coreference score consisting of link-word pair.
		double corefMaxScore = 0.0; //coreference score consisting of maximum of link or word score.
		
		for (String fk : firstLinks.keySet()) {
			
			PairVector firstLinkWithKey = firstLinks.get(fk);
			PairVector secondLinkWithKey = secondLinks.get(fk);
			PairVector secondWordIdx = swordIdx.get(fk);
			
			double lscore = 0.0;
			if (secondLinkWithKey != null)
				lscore = 2.0 * getCoref(firstDoc, secondDoc, windowSize, sf, firstLinkWithKey, secondLinkWithKey);
			double wscore = 0.0;
			if (secondWordIdx != null)
				wscore = getCoref(firstDoc, secondDoc, windowSize, sf, firstLinkWithKey, secondWordIdx);
			
			corefLinkScore += lscore;
			corefWordScore += wscore;
			corefMaxScore += (lscore + 1.0) * wscore;//Math.max(lscore, wscore);

		}
		return corefMaxScore; //max score may not necessarily be the best way to get the coreference, but whatever...
	}
	
	/**
	 * Gets the coreference of the document. Returns the maximum value of coreference seen by calling sf.calculateCoref().
	 * 
	 * @param firstDoc
	 * @param secondDoc
	 * @param windowSize
	 * @param sf
	 * @param firstIdxVec vector containing indices of corresponding word.
	 * @param secondIdxVec
	 * @return the maximum score derived by calling coreference.
	 */
	private static double getCoref(String [] firstDoc, String [] secondDoc, int windowSize, ScoreFunction sf,
									PairVector firstIdxVec, PairVector secondIdxVec) {
		
		double maxScore = - Double.MAX_VALUE;
		for (Pair<Integer, Integer> sk : secondIdxVec) {	
			for (Pair<Integer, Integer> fkidx : firstIdxVec) {
				
				int fidxLeft = fkidx.first;
				int fidxRight = fkidx.second;
				int sidxLeft = sk.first;
				int sidxRight = sk.second;
				
				int fbeginIdx = fidxLeft - windowSize;
				int fendIdx = fidxRight + windowSize;
				int sbeginIdx = sidxLeft - windowSize;
				int sendIdx = sidxRight + windowSize;
				
				double currScore = calculateScore(sf, firstDoc, fbeginIdx, fendIdx, secondDoc, sbeginIdx, sendIdx);
				
				if (currScore > maxScore) maxScore = currScore;
			}
		}		
		return maxScore;
	}
	
	private static double calculateScore(ScoreFunction sf, String [] firstDoc, int fbeginIdx, int fendIdx, 
									String [] secondDoc, int sbeginIdx, int sendIdx) {
		
		fbeginIdx = (fbeginIdx < 0) ? 0 : fbeginIdx;
		sbeginIdx = (sbeginIdx < 0) ? 0 : sbeginIdx;
		fendIdx = (fendIdx >= firstDoc.length) ? firstDoc.length : fendIdx;
		sendIdx = (sendIdx >= secondDoc.length) ? secondDoc.length : sendIdx;
		
		return sf.calculateScore(firstDoc, fbeginIdx, fendIdx, secondDoc, sbeginIdx, sendIdx);
	}
}
